use crate::dao::domain::{account::AccountDao, user::UserDao};
use crate::prelude::*;
use super::user_service::{find_one_user_by_id};
use sqlx::{query, query_as, Encode, Executor, Type};
use uuid::Uuid;
/// account password login
pub async fn ap_login<'e, 'c: 'e, 'f, S, E>(account: S, password: S, e: E) -> AppResult<UserDao>
where
    S: Into<&'f str>,
    E: 'e + Executor<'c, Database = DBType> + Clone,
{
    let account: &str = account.into();
    let password: &str = password.into();

    let e1 = e.clone();
    let account: AccountDao = find_account_by_ap(account, password, e1).await?;
    let e1 = e.clone();
    let user = find_one_user_by_id(account.user_id.ok_or(AppError::NotFound("not found user".into()))?, e1).await?;

    {
        let e1 = e.clone();
        let token = Uuid::new_v4().to_string();
        update_account_token(token.as_str(), &account, e1).await?;
    }
    
    Ok(user)
}

pub async fn find_account_by_ap<'e, 'c: 'e, 'f, S, E>(
    account: S,
    password: S,
    e: E,
) -> AppResult<AccountDao>
where
    S: Into<&'f str>,
    E: 'e + Executor<'c, Database = DBType>,
{
    let account: &str = account.into();
    let password: &str = password.into();
    let password = AccountDao::password_digest(password);

    let sql = format!(
        "SELECT a.* from {account} as a where a.account=? and a.password=? limit 1",
        account = AccountDao::get_table_name()
    );
    let account: AccountDao = query_as(&sql)
        .bind(account)
        .bind(password)
        .fetch_one(e)
        .await?;
    Ok(account)
}
pub async fn update_account_token<'e, 'c: 'e, 'f, S, I, P, E>(
    token: S,
    id: I,
    e: E,
) -> AppResult<()>
where
    S: Into<&'f str>,
    E: 'e + Executor<'c, Database = DBType>,
    I: PrimaryKey<P>,
    for<'a> P: 'a + Encode<'a, DBType> + Type<DBType> + Send,
{
    let token: &str = token.into();

    let sql = format!(
        "UPDATE {account} SET token=? where id=?",
        account = AccountDao::get_table_name()
    );
    query(&sql).bind(token).bind(id.get_pk()).execute(e).await?;
    Ok(())
}

pub async fn ap_register() -> AppResult<()> {
    todo!()
}

#[cfg(test)]
mod tests {
    use super::*;
    #[actix_rt::test]
    async fn test_find_account_by_ap() {
        crate::db_init!().await;
        let account =
            find_account_by_ap("1967629423@qq.com", "123456", crate::get_db_pool!()).await;
        println!("account:{:?}", account);
    }
}
